
package io.renren.modules.oatools.utils.http.temp;

import java.io.IOException;
import java.net.SocketTimeoutException;
import java.security.KeyStore;
import java.security.SecureRandom;
import java.security.cert.X509Certificate;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

import com.alibaba.fastjson.JSON;
import groovy.lang.Binding;
import groovy.lang.GroovyClassLoader;
import groovy.lang.Script;
import io.renren.modules.oatools.utils.http.HttpRequestSend;
import io.renren.modules.oatools.utils.http.OAHttpNetworkInvokeIntercepter;
import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.Headers;
import okhttp3.HttpUrl;
import okhttp3.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
import org.apache.logging.log4j.util.Strings;
import org.codehaus.groovy.runtime.InvokerHelper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.net.ssl.*;

public class OAHttpRequestUtils002 {
    private final static Logger log = LoggerFactory.getLogger(OAHttpRequestUtils002.class);

    // 使用 ThreadLocal 管理重试次数，避免多线程问题
    private static final ThreadLocal<Integer> serversLoadTimes = ThreadLocal.withInitial(() -> 0);
    private static final int maxLoadTimes = 3; // 最大重连次数
    
    // 使用单例 OkHttpClient 实例，避免频繁创建导致的性能问题
    private static final OkHttpClient sharedClient = new OkHttpClient.Builder()
            .connectTimeout(10, TimeUnit.SECONDS)
            .readTimeout(30, TimeUnit.SECONDS)
            .writeTimeout(30, TimeUnit.SECONDS)
            .sslSocketFactory(getSSLSocketFactory(), getX509TrustManager())
            .hostnameVerifier(getHostnameVerifier())
            .build();

    // 获取 SSLSocketFactory
    public static SSLSocketFactory getSSLSocketFactory() {
        try {
            SSLContext sslContext = SSLContext.getInstance("TLS");
            sslContext.init(null, getTrustManager(), new SecureRandom());
            return sslContext.getSocketFactory();
        } catch (Exception e) {
            log.error("获取SSLSocketFactory失败", e);
            return null;
        }
    }

    // 获取 TrustManager
    private static TrustManager[] getTrustManager() {
        return new TrustManager[]{
                new X509TrustManager() {
                    @Override
                    public void checkClientTrusted(X509Certificate[] chain, String authType) {
                    }

                    @Override
                    public void checkServerTrusted(X509Certificate[] chain, String authType) {
                    }

                    @Override
                    public X509Certificate[] getAcceptedIssuers() {
                        return new X509Certificate[]{};
                    }
                }
        };
    }

    // 获取 HostnameVerifier
    public static HostnameVerifier getHostnameVerifier() {
        return (s, sslSession) -> true;
    }

    public static X509TrustManager getX509TrustManager() {
        X509TrustManager trustManager = null;
        try {
            TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
            trustManagerFactory.init((KeyStore) null);
            TrustManager[] trustManagers = trustManagerFactory.getTrustManagers();
            if (trustManagers.length != 1 || !(trustManagers[0] instanceof X509TrustManager)) {
                throw new IllegalStateException("Unexpected default trust managers:" + Arrays.toString(trustManagers));
            }
            trustManager = (X509TrustManager) trustManagers[0];
        } catch (Exception e) {
            log.error("获取X509TrustManager失败", e);
        }

        return trustManager;
    }

    /**
     * 发送 HTTP 请求
     *
     * @param upResponseBody 上游返回的body
     * @param requestSend    本次请求的参数
     * @return 响应结果
     * @throws IOException IO异常
     */
    public static Map<String, Object> requestSend(String upResponseBody, HttpRequestSend requestSend) throws IOException {
        Boolean isSuccess = true;
        Map<String, Object> reMap = new HashMap<>();
        log.info(JSON.toJSONString(requestSend));
        
        // 参数校验
        if (requestSend == null) {
            throw new IllegalArgumentException("requestSend 不能为空");
        }
        
        String requestUrl = requestSend.getRequestUrl() != null ? requestSend.getRequestUrl() : "{}";
        String requestParams = requestSend.getRequestParams() != null ? requestSend.getRequestParams() : "{}";
        String paramsGroovy = requestSend.getParamsGroovy();
        String requestHeaders = requestSend.getRequestHeaders() != null ? requestSend.getRequestHeaders() : "{}";
        String headersGroovy = requestSend.getHeadersGroovy();
        String bodyGroovy = requestSend.getBodyGroovy();
        String requestClientGrooby = requestSend.getRequestClientGrooby();
        String requestBeforeGroovy = requestSend.getRequestBeforeGroovy();
        String requestAfterGroovy = requestSend.getRequestAfterGroovy();
        String reqBody = requestSend.getRequestBody() != null ? requestSend.getRequestBody() : "{}";
        String requestType = requestSend.getRequestType() != null ? requestSend.getRequestType() : "POST";
        int isAsyn = requestSend.getIsAsyn() != null ? Integer.valueOf(requestSend.getIsAsyn().toString()) : 0;

        // 构建 URL
        HttpUrl url = buildUrl(requestUrl, requestParams, paramsGroovy, upResponseBody, reqBody);
        
        // 构建请求头
        Headers headers = buildHeaders(requestHeaders, headersGroovy, upResponseBody, reqBody);
        
        log.info(headers.toString() + "<<<<<<请求地址》》》》》》》》》" + url);

        // 构建 OkHttpClient
        OkHttpClient client = buildClient(requestClientGrooby, upResponseBody, requestSend);

        // 构建请求体
        RequestBody body = buildRequestBody(reqBody, bodyGroovy, upResponseBody, url, headers);

        // 构建请求
        Request request = buildRequest(url, headers, body, requestType, requestBeforeGroovy, upResponseBody);

        // 重置重试次数
        serversLoadTimes.set(0);

        // 执行请求
        if (isAsyn > 0) {
            // 异步请求
            executeAsyncRequest(client, request, reMap, url, upResponseBody, requestAfterGroovy);
        } else {
            // 同步请求
            return executeSyncRequest(client, request, reMap, url, upResponseBody, requestAfterGroovy);
        }
        
        reMap.put("success", isSuccess);
        reMap.put("url", url);
        return reMap;
    }

    /**
     * 构建 URL
     */
    private static HttpUrl buildUrl(String requestUrl, String requestParams, String paramsGroovy, 
                                   String upResponseBody, String reqBody) {
        HttpUrl.Builder urlBuilder = HttpUrl.parse(requestUrl).newBuilder();
        Map returnParamsMap = new HashMap();
        
        if (Strings.isNotEmpty(paramsGroovy)) {
            Object[] executeParamsGroovy = new Object[]{upResponseBody, JSON.parseObject(requestParams, Map.class), reqBody};
            Object executeParamsResult = executeGroovy(executeParamsGroovy, paramsGroovy);
            returnParamsMap = (Map) executeParamsResult;
        } else {
            returnParamsMap = JSON.parseObject(requestParams, Map.class);
        }
        
        returnParamsMap.forEach((key, value) -> {
            urlBuilder.addQueryParameter(key.toString(), value.toString()).build();
            log.info(key + "<<<<<<<>>>>>" + value);
        });
        
        return urlBuilder.build();
    }

    /**
     * 构建请求头
     */
    private static Headers buildHeaders(String requestHeaders, String headersGroovy, 
                                       String upResponseBody, String reqBody) {
        Headers.Builder headersBuilder = new Headers.Builder();
        Map headersMap = JSON.parseObject(requestHeaders, Map.class);

        if (Strings.isNotEmpty(headersGroovy)) {
            Object[] executeHeadersGroovy = new Object[]{upResponseBody, headersMap, reqBody};
            Object executeHeadersResult = executeGroovy(executeHeadersGroovy, headersGroovy);
            headersMap = (Map) executeHeadersResult;
        }
        
        headersMap.forEach((key, value) -> {
            headersBuilder.add(key.toString(), value.toString());
            log.info(key.toString() + "《《《《《《《headers》》》》》》》》" + value.toString());
        });
        
        return headersBuilder.build();
    }

    /**
     * OkHttpClient
     * 配置 HTTP 客户端: 用于设置网络请求的各种参数和行为
     * 构建模式: 使用 Builder 模式来逐步配置客户端选项clientBuilder
     * clientBuilder
     *     .connectTimeout(30, TimeUnit.SECONDS)    // 连接超时
     *     .readTimeout(30, TimeUnit.SECONDS)       // 读取超时
     *     .writeTimeout(30, TimeUnit.SECONDS);     // 写入超时
     *     .addInterceptor(interceptor)             // 应用拦截器
     *     .addNetworkInterceptor(networkInterceptor); // 网络拦截    .authenticator(authenticator)           // 认证器
     *     .sslSocketFactory(sslSocketFactory, trustManager)  // SSL 配置
     *     .hostnameVerifier(hostnameVerifier);    // 主机名验证
     *     .connectionPool(new ConnectionPool(5, 5, TimeUnit.MINUTES)); // 连接池
     *     .proxy(proxy)                           // 设置代理
     *     .proxyAuthenticator(proxyAuthenticator); // 代理认证
     */
    private static OkHttpClient buildClient(String requestClientGrooby, String upResponseBody, 
                                          HttpRequestSend requestSend) {
        OkHttpClient.Builder clientBuilder;
        
        if (Strings.isNotEmpty(requestClientGrooby)) {
            Object[] executeClientGroovy = new Object[]{upResponseBody};
            clientBuilder = (OkHttpClient.Builder) executeGroovy(executeClientGroovy, requestClientGrooby);
        } else {
            // 使用共享的客户端配置
            clientBuilder = sharedClient.newBuilder();
        }
        
        return clientBuilder
                .sslSocketFactory(getSSLSocketFactory(), getX509TrustManager())
                .hostnameVerifier(getHostnameVerifier())
                .addInterceptor(new OAHttpNetworkInvokeIntercepter(requestSend))
                .build();
    }

    /**
     * 构建请求体
     */
    private static RequestBody buildRequestBody(String reqBody, String bodyGroovy, 
                                               String upResponseBody, HttpUrl url, Headers headers) {
        MediaType mediaType = MediaType.parse("application/json");
        RequestBody body = RequestBody.create(mediaType, reqBody);

        if (Strings.isNotEmpty(bodyGroovy)) {
            Object[] executeBodyGroovy = new Object[]{upResponseBody, url, reqBody, headers};
            body = (RequestBody) executeGroovy(executeBodyGroovy, bodyGroovy);
        }
        
        return body;
    }

    /**
     * 构建请求
     */
    private static Request buildRequest(HttpUrl url, Headers headers, RequestBody body, 
                                       String requestType, String requestBeforeGroovy, 
                                       String upResponseBody) {
        Request.Builder requestBuilder = new Request.Builder();
        
        if (Strings.isNotEmpty(requestBeforeGroovy)) {
            Object[] executeBeforeGroovy = new Object[]{upResponseBody, url, body, headers};
            requestBuilder = (Request.Builder) executeGroovy(executeBeforeGroovy, requestBeforeGroovy);
        }
        
        Request request;
        if (requestType.equals("POST")) {
            request = requestBuilder.url(url).post(body).headers(headers).build();
        } else if (requestType.equals("GET")) {
            request = requestBuilder.url(url).get().headers(headers).build();
        } else {
            request = requestBuilder.url(url).build();
        }
        
        return request;
    }

    /**
     * 执行异步请求
     */
    private static void executeAsyncRequest(OkHttpClient client, Request request, 
                                          Map<String, Object> reMap, HttpUrl url,
                                          String upResponseBody, String requestAfterGroovy) {
        Call call = client.newCall(request);
        call.enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                log.error("失败回调 onFailure: " + e.getMessage());
                if (e instanceof SocketTimeoutException && serversLoadTimes.get() < maxLoadTimes) {
                    serversLoadTimes.set(serversLoadTimes.get() + 1);
                    log.error("重连次数: 【" + serversLoadTimes.get() + "】 ");
                    client.newCall(call.request()).enqueue(this);
                } else {
                    log.error("请求失败，无法重试: " + e.getMessage(), e);
                    // 可以考虑添加失败回调机制
                }
            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
                try {
                    if (Strings.isNotEmpty(requestAfterGroovy)) {
                        Object[] executeAfterGroovy = new Object[]{upResponseBody, response};
                        executeGroovy(executeAfterGroovy, requestAfterGroovy);
                    }

                    if (response.isSuccessful()) {
                        if (null != response.body()) {
                            String responseBody = response.body().string();
                            reMap.put("mag", responseBody);
                            log.info("请求后返回数据： " + responseBody);
                        }
                    } else {
                        log.error("token请求接口地址失败：" + url);
                    }
                } finally {
                    if (response.body() != null) {
                        response.body().close();
                    }
                }
            }
        });
    }

    /**
     * 执行同步请求
     */
    private static Map<String, Object> executeSyncRequest(OkHttpClient client, Request request, 
                                                         Map<String, Object> reMap, HttpUrl url,
                                                         String upResponseBody, String requestAfterGroovy) throws IOException {
        Response response = client.newCall(request).execute();
        try {
            if (Strings.isNotEmpty(requestAfterGroovy)) {
                Object[] executeAfterGroovy = new Object[]{upResponseBody, response};
                executeGroovy(executeAfterGroovy, requestAfterGroovy);
            }

            if (response.isSuccessful()) {
                if (null != response.body()) {
                    String responseBody = response.body().string();
                    reMap.put("mag", responseBody);
                    log.info("请求后返回数据： " + responseBody);
                }
            } else {
                log.error("请求接口地址失败：" + url);
            }
            
            reMap.put("success", true);
            reMap.put("url", url);
            return reMap;
        } finally {
            if (response.body() != null) {
                response.body().close();
            }
        }
    }

    /**
     * 执行Groovy脚本
     *
     * @param objects Groovy接收的参数
     * @param groovy  要执行的脚本
     * @return 执行结果
     */
    private static Object executeGroovy(Object[] objects, String groovy) {
        if (Strings.isNotEmpty(groovy)) {
            try (GroovyClassLoader groovyClassLoader = new GroovyClassLoader()) {
                Class<?> scriptClass = groovyClassLoader.parseClass(groovy);
                Script script = InvokerHelper.createScript(scriptClass, new Binding());

                log.info("执行脚本: {}", groovy);
                Object executeResult = script.invokeMethod("execute", objects);
                log.info("执行后返回的值：{}", executeResult);

                return executeResult;
            } catch (Exception e) {
                log.error("Groovy脚本执行失败", e);
                throw new RuntimeException("脚本执行异常: " + e.getMessage(), e);
            }
        }
        return null;
    }

    public static void main(String[] args) throws IOException {
        HttpRequestSend httpRequestSend = new HttpRequestSend();
        httpRequestSend.setRequestUrl("http://localhost:8080/renren-admin/oatools/system/page?order=&orderField=&page=1&limit=10");
        httpRequestSend.setRequestType("GET");
        httpRequestSend.setRequestHeaders("{\"token\":\"6f0e63036af48f2417a327ff108d79b4\"}");
        
        try {
            System.out.println(requestSend(null, httpRequestSend));
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
}